//
//  MTWebServiceClientManager.m
//  XML Test
//
//  Created by jsheriff on 9/21/11.
//  Copyright 2011 The MITRE Corporation. All rights reserved.
//

#import "MTWebServiceClientManager.h"
#import "Notifications.h"

@interface MTWebServiceClientManager ()

- (void)scheduleRetryForRequest:(MTWebServiceRequest *)request;
- (void)retryRequest:(NSTimer*)theTimer;

@end


@implementation MTWebServiceClientManager

@synthesize pendingRequests = iv_pendingRequests;
@synthesize completedRequests = iv_completedRequests;

static MTWebServiceClientManager *sharedWebServiceClientManager = nil;

+ (MTWebServiceClientManager *)sharedManager
{
    if (sharedWebServiceClientManager == nil) {
        sharedWebServiceClientManager = [[super allocWithZone:NULL] init];
    }
    return sharedWebServiceClientManager;
}

+ (id)allocWithZone:(NSZone *)zone
{
    return [[self sharedManager] retain];
}

- (id)copyWithZone:(NSZone *)zone
{
    return self;
}

- (id)retain
{
    return self;
}

- (NSUInteger)retainCount
{
    return NSUIntegerMax;  //denotes an object that cannot be released
}

- (oneway void)release
{
    //do nothing
}

- (id)autorelease
{
    return self;
}

-(id)init {
    self = [super init];
    if (self)
    {
        self.pendingRequests = [[NSMutableArray alloc] init];
        self.completedRequests = [[NSMutableArray alloc] init];
    }
    return self;
}

- (void)postRequestWithId:(CFUUIDRef)uuid toUrl:(NSString *)url message:(NSString *)message retry:(BOOL)retry {    
    // Create the web service object and put it on the queue of pending requests
    MTWebServiceRequest *webServiceRequest = [[MTWebServiceRequest alloc] init];
    webServiceRequest.uuid = uuid;
    webServiceRequest.url = url;
    webServiceRequest.message = message;
    webServiceRequest.status = kPending;
    webServiceRequest.attempts = 1;
    webServiceRequest.receivedData = [[NSMutableData alloc] initWithCapacity:100];
    webServiceRequest.lastStatusCode = 0;
    webServiceRequest.retry = retry;
    [self.pendingRequests addObject:webServiceRequest];
    [webServiceRequest release];
    
    // Create the NSUrl object
	NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:url]];
	[request setHTTPMethod:@"POST"];
	[request setValue:@"text/xml" forHTTPHeaderField:@"Content-Type"];
	[request setHTTPBody:[message dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]];
	[request setValue:[NSString stringWithFormat:@"%d", [message length]] forHTTPHeaderField:@"Content-Length"];
    request.timeoutInterval = 120.0;
    
    // Start the request
    NSLog(@"Posting request to url: %@", url);
    webServiceRequest.connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
}

- (void)retryRequest:(NSTimer*) theTimer {
    // Update the web service object
    MTWebServiceRequest *webServiceRequest = [theTimer userInfo];
    webServiceRequest.status = kPending;
    webServiceRequest.attempts++;
    webServiceRequest.receivedData = [[NSMutableData alloc] initWithCapacity:100];
    webServiceRequest.lastStatusCode = 0;

    // Create the NSUrl object
	NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:webServiceRequest.url]];
	[request setHTTPMethod:@"POST"];
	[request setValue:@"text/xml" forHTTPHeaderField:@"Content-Type"];
	[request setHTTPBody:[webServiceRequest.message dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]];
	[request setValue:[NSString stringWithFormat:@"%d", [webServiceRequest.message length]] forHTTPHeaderField:@"Content-Length"];
    request.timeoutInterval = 120.0;
    
    // Start the request
    NSLog(@"Retrying request to url: %@", webServiceRequest.url);
    webServiceRequest.connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];  
}

- (void)scheduleRetryForRequest:(MTWebServiceRequest *)request {
    request.status = kWaitingForRetry;
    
    double delay = 0.0;
    if (request.attempts <= 1) {
        delay = 5.0;
    }
    else if (request.attempts < 10) {
        delay = request.attempts * 5.0;
    }
    else {
        delay = 120.0;
    }
    
    NSLog(@"Scheduling request for retry with delay: %f", delay);
    [NSTimer scheduledTimerWithTimeInterval:delay target:self selector:@selector(retryRequest:) userInfo:request repeats:NO];
}

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    // Find the matching request
    MTWebServiceRequest *request = nil;
    for (MTWebServiceRequest *obj in self.pendingRequests)
    {
        if (obj.connection == connection)
        {
            request = obj;
            break;
        }
    }

    if (request) {    
        [request.receivedData setLength:0];
    
        if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
            NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
            NSLog(@"     didReceiveResponse with status: %d", httpResponse.statusCode);
            request.lastStatusCode = httpResponse.statusCode;
        }
    }
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    // Find the matching request
    MTWebServiceRequest *request = nil;
    for (MTWebServiceRequest *obj in self.pendingRequests)
    {
        if (obj.connection == connection)
        {
            request = obj;
            break;
        }
    }
    
    if (request) {    
        [request.receivedData appendData:data];
        NSLog(@"     didReceiveData with length: %d", [data length]);
    }
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
    NSLog(@"     didFailWithError: %@ %@", [error localizedDescription], [[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);

    // Find the matching request
    MTWebServiceRequest *request = nil;
    for (MTWebServiceRequest *obj in self.pendingRequests)
    {
        if (obj.connection == connection)
        {
            request = obj;
            break;
        }
    }
    
    if (request) {    
        // release the connection, and the data object
        [request.connection release];
        [request.receivedData release];
        
        if (request.retry) {
            [self scheduleRetryForRequest:request];
            NSDictionary *userInfo = [NSDictionary dictionaryWithObject:request forKey:kWebServiceRequestKey];
            [[NSNotificationCenter defaultCenter] postNotificationName:kWebServiceRequestRetryPending object:self userInfo:userInfo];
        }
        else {
            NSLog(@"Message Failed, no retry requested");
            
            // Move the request to the completed array
            [self.completedRequests addObject:request];
            [self.pendingRequests removeObject:request];
            
            NSDictionary *userInfo = [NSDictionary dictionaryWithObject:request forKey:kWebServiceRequestKey];
            [[NSNotificationCenter defaultCenter] postNotificationName:kWebServiceRequestCompletedWithError object:self userInfo:userInfo];
        }
    }
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    NSLog(@"     connectionDidFinishLoading");
    
    // Find the matching request
    MTWebServiceRequest *request = nil;
    for (MTWebServiceRequest *obj in self.pendingRequests)
    {
        if (obj.connection == connection)
        {
            request = obj;
            break;
        }
    }
    
    if (request) {    
        if (request.lastStatusCode == 200) {
            [request.connection release];
            [request.receivedData release];
            
            request.status = kCompletedWithSuccess;
            NSLog(@"     completedWithSuccess");
            
            // Move the request to the completed array
            [self.completedRequests addObject:request];
            [self.pendingRequests removeObject:request];

            NSDictionary *userInfo = [NSDictionary dictionaryWithObject:request forKey:kWebServiceRequestKey];
            [[NSNotificationCenter defaultCenter] postNotificationName:kWebServiceRequestCompletedWithSuccess object:self userInfo:userInfo];
        }
        else {
            NSString *serverResponse = [[NSString alloc] initWithData:request.receivedData encoding:NSASCIIStringEncoding];
            NSLog(@"     completedWithError: %@", serverResponse);
            
            [request.connection release];
            [request.receivedData release];
            
            request.status = kCompletedWithError;
            
            // Move the request to the completed array
            [self.completedRequests addObject:request];
            [self.pendingRequests removeObject:request];
            
            NSDictionary *userInfo = [NSDictionary dictionaryWithObject:request forKey:kWebServiceRequestKey];
            [[NSNotificationCenter defaultCenter] postNotificationName:kWebServiceRequestCompletedWithError object:self userInfo:userInfo];
        }
	

        
        
    }
}


@end
